
// VS_BEGIN
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aCoord;
layout (location = 2) in vec3 aNormal;
layout (location = 3) in vec3 aTangent;
layout (location = 4) in vec3 aBitangent;

uniform mat4 u_model;

out vec2 TexCoords;
out vec3 WorldPos;
out vec3 Normal;
out mat3 TBN;

layout (std140) uniform EngineUBO
{
    mat4 u_view;
    mat4 u_project;
    vec3 u_camPos;
    vec3 u_camInfo;
    mat4 u_inversePV;
};

void main() {
    WorldPos = vec3(u_model * vec4(aPos, 1.0f)); 
    TexCoords = aCoord;
    Normal = aNormal;
    vec3 T = normalize(vec3(u_model * vec4(aTangent,   0.0)));
    vec3 B = normalize(vec3(u_model * vec4(aBitangent, 0.0)));
    vec3 N = normalize(vec3(u_model * vec4(aNormal,    0.0)));
    TBN = mat3(T, B, N);
    gl_Position = u_project * u_view * vec4(WorldPos, 1.0f);
}
// VS_END
// FS_BEGIN
#version 330 core 

const float PI = 3.14159265359;

// Light Packet:
// position.x position.y position.z type(PointLight: 0; DirectLight: 1; AmbientSphereLight: 2)
// color.r    color.g    color.b    strength
// direct.x   direct.y   direct.z   unuse
// unuse      unuse      unuse      unuse
layout (std140) uniform LightUBO
{
    mat4 u_lights[64];
    int u_lightNum;
};

layout (std140) uniform EngineUBO
{
    mat4 u_view;
    mat4 u_project;
    vec3 u_camPos;
    vec3 u_camInfo;
    mat4 u_inversePV;
};

out vec4 FragColor;

in vec2 TexCoords;
in vec3 WorldPos;
in vec3 Normal;
in mat3 TBN;

uniform samplerCube u_irradianceMap;
uniform samplerCube u_prefilterMap;
uniform sampler2D   u_brdfLUT;

// Texture Offset
uniform vec2 Offset;
uniform vec2 Tiling;


// material parameters
uniform float       UseAlbedoMap;
uniform float       UseMetallicMap;
uniform float       UseRoughnessMap;
uniform float       UseNormalMap;
uniform sampler2D   AlbedoMap;
uniform vec3        Albedo;
uniform sampler2D   MetallicMap;
uniform float       Metallic;
uniform sampler2D   RoughnessMap;
uniform float       Roughness;
uniform sampler2D   NormalMap;



vec3 NormalMapToWorldSpace(vec3 v) {
    v = v * 2.0f - 1.0f;
    return TBN * v;
}

// 混合贴图和数字
vec3 MixMap(vec3 map, vec3 num) {
    if (map == vec3(0.0f)) {
        return num;
    }
    return map;
}

vec3 MixMapNormal(vec3 map, vec3 num) {
    if (map == vec3(0.0f)) {
        return num;
    }
    map = map * 2.0f - 1.0f;
    return TBN * map;
}

// 法线分布函数（D项）
float D_GGX_TR(vec3 N, vec3 H, float a)
{
    float a2     = a*a;
    float NdotH  = max(dot(N, H), 0.0);
    float NdotH2 = NdotH*NdotH;

    float nom    = a2;
    float denom  = (NdotH2 * (a2 - 1.0) + 1.0);
    denom        = PI * denom * denom;

    return nom / denom;
}


float GeometrySchlickGGX(float NdotV, float k)
{
    float nom   = NdotV;
    float denom = NdotV * (1.0 - k) + k;

    return nom / denom;
}
// 几何函数（G项）
float GeometrySmith(vec3 N, vec3 V, vec3 L, float k)
{
    float NdotV = max(dot(N, V), 0.0);
    float NdotL = max(dot(N, L), 0.0);
    float ggx1 = GeometrySchlickGGX(NdotV, k);
    float ggx2 = GeometrySchlickGGX(NdotL, k);

    return ggx1 * ggx2;
}

// 菲涅尔函数（F项）
vec3 FresnelSchlick(vec3 albedo, float metallic, vec3 H, vec3 V)
{
    vec3 F0 = vec3(0.04f);
    F0 = mix(F0, albedo, metallic);
    return F0 + (1.0f - F0) * pow((1.0f - max(dot(H, V), 0.0f)), 5);
}

vec3 FresnelSchlickRoughness(vec3 albedo, float metallic, vec3 N, vec3 V, float roughness)
{
    vec3 F0 = vec3(0.04f);
    F0 = mix(F0, albedo, metallic);
    return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(1.0 - max(dot(N, V), 0.0f), 5.0);
}   

void main() {
    vec2 uv = TexCoords * Tiling + Offset;

    vec3 albedo = mix(Albedo, texture(AlbedoMap, uv).xyz, UseAlbedoMap);
    vec3 normal = normalize(mix(Normal, NormalMapToWorldSpace(texture(NormalMap, uv).xyz), UseNormalMap));
    float metallic = mix(Metallic, texture(MetallicMap, uv).x, UseMetallicMap);
    float roughness = mix(Roughness, texture(RoughnessMap, uv).x, UseRoughnessMap);

    // 视线方向（指向相机）
    vec3 V = normalize(u_camPos - WorldPos);
    // 辐射率总和
    vec3 Lo = vec3(0.0f);
    // 计算普通光源
    for (int i = 0; i < u_lightNum; i++) {
        mat4 light = u_lights[i];

        // 计算直接光照辐射率（忽略环境只关注光源）
        vec3 L = vec3(0.0f);
        float attenuation = 0.0f;
        if (light[0][3] == 0.0f) {  // 点光源
            L = normalize(light[0].xyz - WorldPos); // 光线入射方向 (指向光源)
            float distance = length(light[0].xyz - WorldPos); // 光源到点的距离
            attenuation = 1.0f / (distance * distance + 0.00001f) * light[1].w; // 衰减系数（物体离光源越远越暗）
        } else if (light[0][3] == 1.0f) { // 线光源
            L = normalize(-light[2].xyz);
            attenuation = light[1].w;
        }

        vec3 H = normalize(V + L); // 半程向量   
        vec3 radiance = light[1].rgb * attenuation; // 光源直接照到物体上的辐射率，对应渲染方程中Li(p, Wi)
        float cosTheta = max(dot(normal, L), 0.0f);

        // 计算BRDF
        float D = D_GGX_TR(normal, H, roughness); // 计算法线分布函数

        // 普通光源
        float k = (roughness + 1) * (roughness + 1) / 8;
        // IBL光源
        // float k = (roughness * roughness) / 2;
        float G = GeometrySmith(normal, V, L, k); // 计算几何函数
        
        vec3 F = FresnelSchlick(albedo, metallic, H, V); // 菲涅尔函数

        vec3 Ks = F;
        vec3 Kd = vec3(1.0f) - F;
        vec3 BRDF = Kd * (albedo / PI) + Ks * (D * G * F) / (4 * max(dot(V, normal), 0.0f) * max(dot(L, normal), 0.0f) + 0.00001f);

        // 计算最终辐射率
        Lo += BRDF * radiance * cosTheta;
    }
    // 计算IBL光源
    vec3 kS = FresnelSchlickRoughness(albedo, metallic, normal, V, roughness); // 菲涅尔函数
    vec3 kD = 1.0 - kS;
    kD *= 1.0 - metallic;

    vec3 irradiance = texture(u_irradianceMap, normal).rgb;
    vec3 diffuse    = kD * irradiance * albedo;

    vec3 R = reflect(-V, normal);
    const float MAX_REFLECTION_LOD = 4.0;
    vec3 prefilteredColor = textureLod(u_prefilterMap, R,  roughness * MAX_REFLECTION_LOD).rgb;   
    vec2 envBRDF  = texture(u_brdfLUT, vec2(max(dot(normal, V), 0.0), roughness)).rg;
    vec3 specular = prefilteredColor * (kS * envBRDF.x + envBRDF.y);

    vec3 ambient    = diffuse + specular;
    
    FragColor = vec4(ambient + Lo, 1.0f);
}
// FS_END
